/**
 * 
 */
package com.zznode.client.wlanpolling.model;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.DhcpInfo;
import android.net.wifi.WifiInfo;
import android.util.Log;

import com.zznode.client.wlanpolling.WLanContext;
import com.zznode.client.wlanpolling.service.Wifi;
import com.zznode.client.wlanpolling.service.net.EnumHttpMethod;
import com.zznode.client.wlanpolling.service.net.HttpCallback;
import com.zznode.client.wlanpolling.service.net.HttpExecutorFactory;
import com.zznode.client.wlanpolling.service.net.HttpGetExecutor;
import com.zznode.client.wlanpolling.service.net.HttpParam;
import com.zznode.client.wlanpolling.service.net.HttpPostExecutor;
import com.zznode.client.wlanpolling.utils.NetworkUtils;
import com.zznode.client.wlanpolling.utils.PingUtils;
import com.zznode.client.wlanpolling.utils.WLanPollingUtils;
import com.zznode.global.Global;

/**
 * 
 *
 */
public class WLANPollManager {
	// 所有的资源确认信息，Key为bssid(mac)，Value为WlanInfo，全局状态保存
	public final Map<String, WLanInfo> allInfo = Collections
			.synchronizedMap(new HashMap<String, WLanInfo>());

	// 当前接入点的测试结果
	private TestResult testResult = new TestResult();
	private List<WirelessEnvApInfo> wirelessEnvResult;
	//private List<WebSiteResult> webSiteResult;

	private static WLANPollManager instance;
	
	private SQLiteDatabase readonlyDb;
	private Cursor realonlyCursor;
	private String currHotType;
	
	public synchronized static WLANPollManager getWLANPollManager() {
		if (instance == null) {
			instance = new WLANPollManager();
		}
		return instance;
	}
	
	public static void init() {
	}
	
	public static void destory() {
		if(!instance.realonlyCursor.isClosed()) {
			instance.realonlyCursor.close();
		}
		
		if(instance.readonlyDb.isOpen()) {
			instance.readonlyDb.close();
		}
	}
	
	private WLANPollManager() {
	}
	
	private String getValue(String name, String value) {
		Map<String, String> map =  new HashMap<String,String>(); 
		Map<String, Map<String, String>> map2 = new HashMap<String, Map<String, String>>();
		map2 = Global.map;
		boolean isDisc = false;
		if(name.equals("apCoverTech")){
			map = Global.hotspotsovtechMap;
			isDisc = true;
		}
		else if(name.equals("iscoverbyap")){
			map = Global.iscoverbyapMap;
			isDisc = true;
		}
		else if (name.equals("hottype")) {
			map = Global.hotspottypeMap;
			isDisc = true;
		}
		else if(name.equals("apTranType")){
			map = Global.transmissiontypeMap;
			isDisc = true;
		}
		else if(name.equals("hotsubtype")){
			isDisc = true;
				currHotType = testResult.getHotType();
				if(currHotType != null)
					map = map2.get(currHotType);
		}
		if (value != null && map !=null) {
			if(isDisc){
				value = map.get(value);
				return value;
			}
			else return value;
			
		}
		else {
			return null;
		}
		
	}
	
	/**
	 * 提交测试结果和设备信息
	 * 
	 * @param callback
	 */
	public void postTestResult(HttpCallback callback, int tag, String userName ) {
		HttpPostExecutor executor = (HttpPostExecutor) HttpExecutorFactory
				.createHttpExecutor(EnumHttpMethod.POST);
		executor.setUrl(WLanPollingUtils.getUpdatePollingURL());
		
		try {
			for (Field field : TestResult.class.getFields()) {
				
				String value = (String) field.get(testResult);
				String name = field.getName();
				if(name.equals("username")){
					value = userName;
				}
				value = getValue(name, value);
				System.err.println("name:"+name+":value:"+value);
				if (value != null && value.length() > 0)
					executor.addParam(new HttpParam(name, value));
			}
		} catch (Exception e) {
			Log.d(WLANPollManager.class.getName(), e.getMessage());
		}

		executor.asyncExecute(callback, tag);
	}

	/**
	 * 更新无线环境信息
	 * 
	 * @param callback
	 */
	public void postWirelessEnv(HttpCallback callback, int tag) {
		HttpPostExecutor executor = (HttpPostExecutor) HttpExecutorFactory
				.createHttpExecutor(EnumHttpMethod.POST);
		executor.setUrl(WLanPollingUtils.getUpdateWirelessEnv());

		Map<String, String> params = new HashMap<String, String>();

		try {
			for (WirelessEnvApInfo apInfo : wirelessEnvResult) {
				for (Field field : WirelessEnvApInfo.class.getFields()) {
					String value = (String) field.get(apInfo);
					String name = field.getName();
					String values = params.get(name);
					if (values != null && !"curApMac".equals(name)) {
						values += ("," + value);
					} else {
						values = value;
					}
					params.put(name, values);
				}
			}
		} catch (Exception e) {
			Log.d(WLANPollManager.class.getName(), e.getMessage());
		}

		for (Entry<String, String> entry : params.entrySet()) {
			executor.addParam(new HttpParam(entry.getKey(), entry.getValue()));
		}

		executor.asyncExecute(callback, tag);
	}

	public void postWebSiteResult(HttpCallback callback, int tag) {
		HttpPostExecutor executor = (HttpPostExecutor) HttpExecutorFactory
				.createHttpExecutor(EnumHttpMethod.POST);
		executor.setUrl(WLanPollingUtils.getUpdateWirelessEnv());

	}

	/**
	 * 当前测试结果
	 * 
	 * @return
	 */
	public TestResult getTestResult() {
		return testResult;
	}
	
	public TestResult getTestResult(Context ctx, Integer _id) {
		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Field[] fields = TestResult.class.getFields();

		List<String> colums = new ArrayList<String>();
		for (Field f : fields) {
			colums.add(f.getName());
		}

		Cursor cursor = db.query(DatabaseHelper.TABLE_TESTRESULT,
				colums.toArray(new String[0]), "id='" + _id + "'", null,
				null, null, null);
		
		TestResult result = null;
		if (cursor.moveToFirst()) {
			result = new TestResult();
			for (int i = 0; i < colums.size(); i++) {
				String value = cursor.getString(i);
				try {
					fields[i].set(result, value);
				} catch (Exception e) {
				}
			}
		}

		cursor.close();
		db.close();
		
		return result;
	}
	
	/**
	 * 当前无线环境信息
	 * 
	 * @param context
	 * @param apMac
	 * @return
	 */
	public List<WirelessEnvApInfo> getWirelessEnvResult(Context context,
			String apMac) {
		if (wirelessEnvResult == null || wirelessEnvResult.size() == 0) {
			loadWirelessEnvFromDb(context, apMac);
		}
		return wirelessEnvResult;
	}

	/**
	 * 更新测试结果到DB
	 * 
	 * @param ctx
	 * @param wifiInfo
	 * @param dhcpInfo
	 * @param wLanContext
	 */
	public void updateTestResult(Context ctx, WifiInfo wifiInfo,
			DhcpInfo dhcpInfo, WLanContext wLanContext) {
		String apMac = wifiInfo.getBSSID().replace(":", " ");

		loadTestResultFromDb(ctx, apMac);

		// 基本信息
		testResult.uid = wLanContext.getUid();
		testResult.areaid = wLanContext.getAreaId();
		testResult.citycode = wLanContext.getCityCode();
		testResult.apMac = apMac;
		testResult.hotname = wifiInfo.getSSID();
		testResult.ipAddress = NetworkUtils.intToIp(dhcpInfo.ipAddress);

		Map<String, Object> values = new HashMap<String, Object>();

		values.put(TestResultConstants.UID, testResult.uid);
		values.put(TestResultConstants.AREAID, testResult.areaid);
		values.put(TestResultConstants.CITYCODE, testResult.citycode);
		values.put(TestResultConstants.APMAC, apMac);
		values.put(TestResultConstants.HOTNAME, testResult.hotname);
		values.put(TestResultConstants.IPADDRESS, testResult.ipAddress);
		values.put(TestResultConstants.SSID, testResult.hotname);
		
		updateTestResult(ctx, apMac, values);
	}

	/**
	 * 保存测试结果到db
	 * 
	 * @param ctx
	 */
	public void saveTestResultToDB(Context ctx) {
		if (testResult != null && testResult.apMac != null
				&& testResult.apMac.length() > 0) {
			Map<String, Object> values = new HashMap<String, Object>();
			Field[] fields = TestResult.class.getFields();

			for (Field field : fields) {
				String name = field.getName();
				String value = null;
				try {
					value = (String) field.get(testResult);
				} catch (Exception e) {
				}

				values.put(name, value);
			}

			updateTestResult(ctx, testResult.apMac, values);
		}
	}

	/**
	 * 加载当前AP的最近一次测试结果
	 * 
	 * @param ctx
	 * @param apMac
	 */
	public void loadTestResultFromDb(Context ctx, String apMac) {
		apMac = PingUtils.clearMacAdress(apMac);

		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Field[] fields = TestResult.class.getFields();

		List<String> colums = new ArrayList<String>();
		for (Field f : fields) {
			colums.add(f.getName());
		}

		Cursor cursor = db.query(DatabaseHelper.TABLE_TESTRESULT,
				colums.toArray(new String[0]), "apMac='" + apMac + "'", null,
				null, null, null);

		if (cursor.moveToFirst()) {
			testResult = new TestResult();
			for (int i = 0; i < colums.size(); i++) {
				String value = cursor.getString(i);
				try {
					fields[i].set(testResult, value);
				} catch (Exception e) {
				}
			}
		}

		cursor.close();
		db.close();
	}
	
	public Cursor loadTestResultCursorFromDb(Context ctx) {
		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		
		if(readonlyDb == null || !readonlyDb.isOpen()) {
			readonlyDb = dbHelper.getReadableDatabase();
		}
		
		if(realonlyCursor == null || realonlyCursor.isClosed()) {
			//realonlyCursor = readonlyDb.query(DatabaseHelper.TABLE_TESTRESULT, new String[]{"id", "sysApMac", "ssid", "testtime"}, null, null, null, null, " testtime desc ");
			realonlyCursor = readonlyDb.rawQuery("select id as _id, apMac, ssid, testtime from " + DatabaseHelper.TABLE_TESTRESULT, null);
		}
		
		return realonlyCursor;
	}

	/**
	 * 加载无线环境信息
	 * 
	 * @param ctx
	 * @param apMac
	 */
	public void loadWirelessEnvFromDb(Context ctx, String apMac) {
		apMac = PingUtils.clearMacAdress(apMac);
		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Field[] fields = WirelessEnvApInfo.class.getFields();
		List<String> colums = new ArrayList<String>();
		for (Field f : fields) {
			colums.add(f.getName());
		}

		wirelessEnvResult = new ArrayList<WirelessEnvApInfo>();
		Cursor cursor = db.query(DatabaseHelper.TABLE_WIRELESSENVAPINFO,
				colums.toArray(new String[0]), "curApMac='" + apMac + "'",
				null, null, null, null);

		if (cursor.moveToFirst()) {
			WirelessEnvApInfo wirelessEnvApInfo = new WirelessEnvApInfo();
			for (int i = 0; i < colums.size(); i++) {
				String value = cursor.getString(i);
				try {
					fields[i].set(wirelessEnvApInfo, value);
				} catch (Exception e) {
				}
			}
			wirelessEnvResult.add(wirelessEnvApInfo);
		}

		cursor.close();
		db.close();
	}

	/**
	 * 更新Map中的测试结果，values的key必须是字段名称
	 * 
	 * @param ctx
	 * @param apMac
	 * @param values
	 */
	public void updateTestResult(Context ctx, String apMac,
			Map<String, Object> values) {
		apMac = PingUtils.clearMacAdress(apMac);
		String where = "apMac='" + apMac + "'";

		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Cursor cursor = db.query(DatabaseHelper.TABLE_TESTRESULT,
				new String[] { "id" }, where, null, null, null, null);
		ContentValues contentValues = new ContentValues();

		for (Entry<String, Object> entry : values.entrySet()) {
			String name = entry.getKey();
			String value = "";
			if (entry.getValue() != null) {
				value = entry.getValue().toString();
			}
			contentValues.put(name, value);
			try {
				Field field = TestResult.class.getField(name);
				if (value != null) {
					field.set(testResult, value);
				}
			} catch (Exception e) {
			}

		}

		/**
		 * 最后一次更新时间
		 */
		contentValues.put("testtime", new Date().toLocaleString());
		contentValues.put("apMac", apMac);
		if (cursor.moveToFirst()) {
			int affected = db.update(DatabaseHelper.TABLE_TESTRESULT,
					contentValues, where, null);
			if (affected <= 0) {
				Log.d(WLANPollManager.class.getName(), "update failed!");
			}
		} else {
			// create
			long id = db.insert(DatabaseHelper.TABLE_TESTRESULT, "apMac",
					contentValues);
			if (id < 0) {
				Log.d(WLANPollManager.class.getName(), "insert failed!");
			}
		}
		cursor.close();
		db.close();
	}

	/**
	 * 获取已经测试过的AP的mac地址
	 * 
	 * @param ctx
	 * @return
	 */
	public Set<String> getTestApSet(Context ctx) {
		Set<String> set = new HashSet<String>();

		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Cursor cursor = db.query(DatabaseHelper.TABLE_TESTRESULT,
				new String[] { "apMac" }, null, null, null, null, null);

		while (cursor.moveToNext()) {
			String apMac = cursor.getString(0);
			if (apMac != null && !set.contains(apMac)) {
				set.add(apMac);
			}
		}

		cursor.close();
		db.close();

		return set;
	}

	public void postWebSiteResult(HttpCallback callback, String apMac, String name,
			String url, String maxSpeed, String avgSpeed, String minSpeed) {

		HttpGetExecutor executor = (HttpGetExecutor) HttpExecutorFactory
				.createHttpExecutor(EnumHttpMethod.GET);
		executor.setUrl(WLanPollingUtils.getUpdateWebSiteResultURL());

		apMac = PingUtils.clearMacAdress(apMac);
		
		executor.addParam(new HttpParam("curApMac", apMac));
		executor.addParam(new HttpParam("netname", name));
		executor.addParam(new HttpParam("netaddr", url));
		executor.addParam(new HttpParam("maxratio", maxSpeed));
		executor.addParam(new HttpParam("averageratio", avgSpeed));
		executor.addParam(new HttpParam("minratio", minSpeed));
		
		executor.asyncExecute(callback, 0);
		
		/**
		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();

		Cursor cursor = db.query(DatabaseHelper.TABLE_TESTRESULT,
				new String[] { "apMac" }, null, null, null, null, null);

		ContentValues values = new ContentValues();

		values.put("name", name);
		values.put("url", url);
		values.put("speed", speed);
		values.put("avgSpeed", avgSpeed);
		values.put("apMac", apMac);

		if (cursor.moveToFirst()) {
			// update
			db.update(DatabaseHelper.TABLE_WEBSITERESULT, values, "apMac=?",
					new String[] { apMac });
		} else {
			// insert
			db.insert(DatabaseHelper.TABLE_WEBSITERESULT, "apMac", values);
		}

		cursor.close();
		db.close();
		*/
	}

	/**
	 * 更新邻频干扰信息
	 * 
	 * @param applicationContext
	 * @param bssid
	 * @param sameFrequencyInterference
	 * @param nearbyFrequencyInterference
	 */
	public void updateWirelessEnv(Context ctx, String apMac,
			List<Wifi> sameFrequencyInterference,
			List<Wifi> nearbyFrequencyInterference) {
		apMac = PingUtils.clearMacAdress(apMac);
		wirelessEnvResult = new ArrayList<WirelessEnvApInfo>();

		if (sameFrequencyInterference != null
				&& sameFrequencyInterference.size() > 0) {
			for (Wifi wifi : sameFrequencyInterference) {
				WirelessEnvApInfo wirelessEnvApInfo = new WirelessEnvApInfo();
				wirelessEnvApInfo.curApMac = apMac;
				wirelessEnvApInfo.nearmac = PingUtils.clearMacAdress(wifi
						.getBSSID());
				wirelessEnvApInfo.nearChannel = NetworkUtils.getChannel(wifi
						.getFrequency()) + "";
				wirelessEnvApInfo.nearfrquency = wifi.getFrequency() + "";
				wirelessEnvApInfo.nearssidname = wifi.getSSID();
				wirelessEnvApInfo.nearrssi = wifi.getRssi() + "";
				// TODPO
				wirelessEnvApInfo.neartype = "同频干扰";

				wirelessEnvResult.add(wirelessEnvApInfo);
			}
		}

		if (nearbyFrequencyInterference != null
				&& nearbyFrequencyInterference.size() > 0) {
			for (Wifi wifi : nearbyFrequencyInterference) {
				WirelessEnvApInfo wirelessEnvApInfo = new WirelessEnvApInfo();

				wirelessEnvApInfo.curApMac = apMac;
				wirelessEnvApInfo.nearmac = wifi.getBSSID();
				wirelessEnvApInfo.nearChannel = NetworkUtils.getChannel(wifi
						.getFrequency()) + "";
				wirelessEnvApInfo.nearfrquency = wifi.getFrequency() + "";
				wirelessEnvApInfo.nearssidname = wifi.getSSID();
				wirelessEnvApInfo.nearrssi = wifi.getRssi() + "";
				// TODO
				wirelessEnvApInfo.neartype = "邻频干扰";

				wirelessEnvResult.add(wirelessEnvApInfo);
			}
		}

		// delete old data
		DatabaseHelper dbHelper = new DatabaseHelper(ctx);
		SQLiteDatabase db = dbHelper.getWritableDatabase();
		String where = "curApMac='" + apMac + "'";

		db.delete(DatabaseHelper.TABLE_WIRELESSENVAPINFO, where, null);

		for (WirelessEnvApInfo wirelessEnvApInfo : wirelessEnvResult) {
			ContentValues contentValues = new ContentValues();

			for (Field field : wirelessEnvApInfo.getClass().getFields()) {
				String name = field.getName();
				Object value = null;
				try {
					value = field.get(wirelessEnvApInfo);
				} catch (Exception e) {
				}
				contentValues.put(name, value == null ? "" : value.toString());
			}

			db.insert(DatabaseHelper.TABLE_WIRELESSENVAPINFO, "curApMac",
					contentValues);
		}

		db.close();
	}
	
	public void postBreakdownInfo(HttpCallback callback, String apMac, String faultDesc) {
		HttpGetExecutor executor = (HttpGetExecutor)HttpExecutorFactory.createHttpExecutor(EnumHttpMethod.GET);
		executor.setUrl(WLanPollingUtils.getBreakdownUrl());
		
		executor.addParam(new HttpParam("sysApMac", PingUtils.clearMacAdress(apMac)));
		executor.addParam(new HttpParam("faultDesc", faultDesc));
		
		executor.asyncExecute(callback, 0);
	}

	
	
	public void postResourceInfo(HttpCallback callback,
			String bssid, Map<String, Object> values) {
		HttpPostExecutor executor = (HttpPostExecutor) HttpExecutorFactory.createHttpExecutor(EnumHttpMethod.POST);
		executor.setUrl(WLanPollingUtils.getUpdatePollingURL());

		for(Map.Entry<String, Object> entry : values.entrySet()) {
			if(entry.getValue() != null) {
				String value = getValue(entry.getKey(), entry.getValue().toString());
				System.err.println("entry.getKey():"+entry.getKey()+":value:"+value);
				executor.addParam(new HttpParam(entry.getKey(), value));
			}
		}

		executor.asyncExecute(callback, 1);
	}

}
